package com.redepronik.negosyscom.invfac.controller;

import static com.redepronik.negosys.utils.Utils.parametro;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.primefaces.context.RequestContext;
import org.primefaces.event.CellEditEvent;
import org.primefaces.event.SelectEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;

import com.redepronik.negosys.invfac.entity.Bodega;
import com.redepronik.negosys.invfac.entity.Detalleegreso;
import com.redepronik.negosys.invfac.entity.Egreso;
import com.redepronik.negosys.invfac.entity.Entrada;
import com.redepronik.negosys.invfac.entity.Guiaremision;
import com.redepronik.negosys.invfac.entity.Kardex;
import com.redepronik.negosys.invfac.entity.Local;
import com.redepronik.negosys.invfac.entity.Motivotraslado;
import com.redepronik.negosys.invfac.entity.Producto;
import com.redepronik.negosys.invfac.entityAux.CantidadFactura;
import com.redepronik.negosys.invfac.entityAux.FacturaReporte;
import com.redepronik.negosys.invfac.entityAux.PersonaCedulaNombre;
import com.redepronik.negosys.invfac.service.EgresoService;
import com.redepronik.negosys.invfac.service.KardexService;
import com.redepronik.negosys.invfac.service.LocalService;
import com.redepronik.negosys.invfac.service.MotivoTrasladoService;
import com.redepronik.negosys.invfac.service.ProductoService;
import com.redepronik.negosys.invfac.service.TipoDocumentoService;
import com.redepronik.negosys.invfac.service.TipoPagoService;
import com.redepronik.negosys.rrhh.entity.Empleadocargo;
import com.redepronik.negosys.rrhh.entity.Persona;
import com.redepronik.negosys.rrhh.service.ClienteService;
import com.redepronik.negosys.rrhh.service.EmpleadoService;
import com.redepronik.negosys.rrhh.service.PersonaService;
import com.redepronik.negosyscom.invfac.report.EgresoReport;

@Controller
@Scope("session")
public class FacturaRapidaBean implements Serializable {

	private static final long serialVersionUID = 1L;

	@Autowired
	private MotivoTrasladoService motivoTrasladoService;

	@Autowired
	private EgresoService egresoService;

	@Autowired
	private ProductoService productoService;

	@Autowired
	private KardexService kardexService;

	@Autowired
	private ClienteService clienteService;

	@Autowired
	private LocalService localService;

	@Autowired
	private TipoDocumentoService tipoDocumentoService;

	@Autowired
	private TipoPagoService tipoPagoService;

	@Autowired
	private PersonaService personaService;

	@Autowired
	private EgresoReport egresoReport;

	@Autowired
	private EmpleadoService empleadoService;

	private List<Local> listaLocales;
	private List<Motivotraslado> listaMotivotraslados;
	private List<PersonaCedulaNombre> listaVendedores;
	private List<PersonaCedulaNombre> listaTransportistas;

	private Egreso egreso;
	private Persona cliente;
	private Empleadocargo vendedor;
	private Empleadocargo transportista;

	private Guiaremision guiaRemision;
	private boolean guia;

	private Producto producto;

	private List<FacturaReporte> listaFacturaReporte;
	private FacturaReporte facturaReporte;
	private CantidadFactura cantidadFacturaCalculos;
	private CantidadFactura cantidadFacturaPresentar;
	private BigDecimal restante;
	private BigDecimal restanteAux;
	private BigDecimal cambio;
	private BigDecimal totalMonto;

	private Integer cantidad;
	private BigDecimal nuevoPrecio;

	private Bodega bodega;
	private Integer fila;

	private boolean bn = true;

	public FacturaRapidaBean() {
		cliente = new Persona();
		producto = new Producto();
		listaFacturaReporte = new ArrayList<FacturaReporte>();
		listaFacturaReporte.add(new FacturaReporte());
		facturaReporte = new FacturaReporte();
		cantidadFacturaCalculos = new CantidadFactura();
		cantidadFacturaPresentar = new CantidadFactura();
		restante = new BigDecimal("0.00");
		cambio = new BigDecimal("0.00");
		totalMonto = new BigDecimal("0");
	}

	private void cambiarCantidad() {
//		FacturaReporte f = listaFacturaReporte.get(fila);
//		int can = kardexService.obtenerSaldoActual(f.getCodigo(),
//				bodega.getBodegaid()).getCantidad();
//
//		if (cantidad > can || cantidad <= 0)
//			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
//					"ERROR", "INGRESE UNA CANTIDAD MENOR A LA EXISTENTE: "
//							+ can + " O MAYOR QUE CERO"));
//		else if (cantidad != f.getCantidad())
//			listaFacturaReporte.set(fila, egresoService.recalcular(fila, f,
//					egreso.getDetalleegresos(), cantidadFacturaCalculos,
//					cantidad, null, true));
//
//		cantidad = null;
//		fila = null;
	}

	public void cambiarPrecio() {
//		FacturaReporte f = listaFacturaReporte.get(fila);
//
//		BigDecimal precio = productoService.obtenerPorProductoId(
//				f.getProductoId()).getPrecio();
//		if (nuevoPrecio.compareTo(precio) < 0)
//			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
//					"ERROR", "EL PRECIO NO DEBE SER MENOR AL PRECIO DE COSTO: "
//							+ precio));
//		else if (nuevoPrecio != f.getPrecioUnitVenta())
//			listaFacturaReporte.set(fila, egresoService.recalcular(fila, f,
//					egreso.getDetalleegresos(), cantidadFacturaCalculos, null,
//					nuevoPrecio, true));
//
//		nuevoPrecio = null;
//		fila = null;
	}

	public void cancelarTodo() {
		bn = true;
		xxx();
		cliente = new Persona();
		listaFacturaReporte = new ArrayList<FacturaReporte>();
		listaFacturaReporte.add(new FacturaReporte());
		cantidadFacturaCalculos = new CantidadFactura();
		restante = new BigDecimal("0.00");
		cambio = new BigDecimal("0.00");
	}

	public void cantidad() {
		if (fila.compareTo(listaFacturaReporte.size() - 1) == 0)
			insertarDetalle();
		else
			cambiarCantidad();
	}

	public void cargarCliente(SelectEvent event) {
		cliente = clienteService.obtenerPorPersonaId(cliente.getPersonaid());
		egreso.setCliente(cliente.getCliente());
	}

	public void cargarProducto() {
		if (comprobarClienteLocal()) {
			if (fila.compareTo(0) == 0)
				metodo();
			else if (listaFacturaReporte.get(fila - 1).getCantidad() != null)
				metodo();
		}
	}

	public void comprobarCabecera() {
		RequestContext context = RequestContext.getCurrentInstance();
		boolean error = false;
		if (guia) {
			if (guiaRemision.getMotivotraslado().getMotivotrasladoid() == 0) {
				error = true;
				presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"MENSAJE DEL SISTEMA",
						"ERROR: INGRESE UN MOTIVO DE TRNASLADO"));
			} else if (guiaRemision.getPlaca().compareTo("") == 0) {
				error = true;
				presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"MENSAJE DEL SISTEMA", "ERROR: INGRESE UNA PLACA"));
			} else if (transportista.getEmpleadocargoid() == 0) {
				error = true;
				presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"MENSAJE DEL SISTEMA",
						"ERROR: INGRESE UN TRANSPORTISTA"));
			}

		}
		if (cliente.getCliente() == null) {
			error = true;
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"MENSAJE DEL SISTEMA", "ERROR: INGRESE UN CLIENTE"));
			System.out.println("entre en cliente");
		} else if (egreso.getLocal().getLocalid() == null) {
			error = true;
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"MENSAJE DEL SISTEMA", "ERROR: ESCOJA UN LOCAL"));
			System.out.println("entre en local");
		} else if (egreso.getCodigodocumento() == null) {
			error = true;
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"MENSAJE DEL SISTEMA",
					"ERROR: INGRESE UN CODIGO DE DOCUMENTO"));
			System.out.println("entre en documento");
		} else if (vendedor.getEmpleadocargoid() == 0) {
			error = true;
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"MENSAJE DEL SISTEMA", "ERROR: INGRESE UN VENDEDOR"));
			System.out.println("entre en vendedor");
		}
		System.out.println(vendedor.getEmpleadocargoid());

		if (error)
			context.addCallbackParam("error", true);
		else
			context.addCallbackParam("error", false);
	}

	public boolean comprobarCantidadFinal() {
		boolean bn = true;

		List<Detalleegreso> detalleEgreso = egresoService
				.duplicarDetalleEgreso(egreso.getDetalleegresos());

		List<Detalleegreso> detalleEgresoFinal = egresoService
				.sumarCantidades(detalleEgreso);
		for (Detalleegreso de : detalleEgresoFinal) {

			Producto producto = productoService.obtenerPorProductoId(de
					.getProducto().getProductoid());

			int cantidad = kardexService.obtenerSaldoActual(producto.getEan(),
					bodega.getBodegaid()).getCantidad();

			if (de.getCantidad() > cantidad) {
				bn = false;
				presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"ERROR", "LA SUMA DE LAS CANTIDADES DEL PRODUCTO: "
								+ producto.getEan() + " ES MAYOR A: "
								+ cantidad));
			}
		}

		return bn;
	}

	public boolean comprobarClienteLocal() {
		boolean bn = true;
		if (egreso.getCliente() == null) {
			bn = false;
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"ERROR", "DEBE ESCOJER PRIMERO UN CLIENTE"));
		}
		if (egreso.getLocal().getLocalid() == null) {
			bn = false;
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"ERROR", "DEBE ESCOJER UN LOCAL"));
		}
		if (egreso.getLocal().getLocalid() != null) {
			Local local = localService.obtenerPorLocalId(egreso.getLocal()
					.getLocalid());
			if (local.getBodegalocals() == null
					&& local.getBodegalocals().isEmpty()) {
				bn = false;
				presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"ERROR",
						"EL LOCAL QUE ESCOJIO NO TIENE BODEGAS ASOCIADAS"));
			}
		}

		return bn;
	}

	public boolean comprobarDetalleEgreso() {
		RequestContext context = RequestContext.getCurrentInstance();
		boolean bn = true;

		if (egreso.getDetalleegresos().isEmpty()) {
			bn = false;
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"ERROR", "DEBE INGRESAR DETALLES"));
		}

		if (bn)
			context.addCallbackParam("error", true);
		else
			context.addCallbackParam("error", false);

		return bn;
	}

	public void comprobarGuiaRemision() {
		String mensaje = guia ? "LA FACTURA TENDRA GUIA DE REMISION"
				: "LA FACTURA NO TENDRA GUIA DE REMISION";
		presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_INFO,
				"MENSAJE DEL SISTEMA", "AVISO: " + mensaje));
	}

	public void eliminarDetalle(ActionEvent actionEvent) {
		int posicion = egresoService.posicion(facturaReporte,
				egreso.getDetalleegresos(), true);
		if (posicion >= 0) {
			Detalleegreso de = egreso.getDetalleegresos().get(posicion);
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_INFO,
					"ELIMINÓ DETALLE", "Elimino: " + de.getProducto().getEan()));
			egreso.removeDetalleegreso(de);
			cantidadFacturaCalculos = egresoService.calcularCantidadFactura(
					cantidadFacturaCalculos, facturaReporte, "subtract");
			restante = restanteAux = cantidadFacturaCalculos.getTotal();
			listaFacturaReporte.remove(facturaReporte);
			limpiarFacturaReporte();
		}
	}

	public BigDecimal getCambio() {
		return cambio;
	}

	public Integer getCantidad() {
		return cantidad;
	}

	public CantidadFactura getCantidadFacturaCalculos() {
		return cantidadFacturaCalculos;
	}

	public CantidadFactura getCantidadFacturaPresentar() {
		return egresoService.redondearCantidadFactura(cantidadFacturaPresentar,
				cantidadFacturaCalculos);
	}

	public Persona getCliente() {
		return cliente;
	}

	public Egreso getEgreso() {
		return egreso;
	}

	public FacturaReporte getFacturaReporte() {
		return facturaReporte;
	}

	public List<FacturaReporte> getFacturaReportes() {
		return listaFacturaReporte;
	}

	public Guiaremision getGuiaRemision() {
		return guiaRemision;
	}

	public List<Local> getListaLocales() {
		return listaLocales;
	}

	public List<Motivotraslado> getListaMotivotraslados() {
		return listaMotivotraslados;
	}

	public List<PersonaCedulaNombre> getListaTransportistas() {
		return listaTransportistas;
	}

	public List<PersonaCedulaNombre> getListaVendedores() {
		return listaVendedores;
	}

	public BigDecimal getNuevoPrecio() {
		return nuevoPrecio;
	}

	public Producto getProducto() {
		return producto;
	}

	public BigDecimal getRestante() {
		return restante;
	}

	public BigDecimal getRestanteAux() {
		return restanteAux;
	}

	public BigDecimal getTotalMonto() {
		return totalMonto;
	}

	public Empleadocargo getTransportista() {
		return transportista;
	}

	public Empleadocargo getVendedor() {
		return vendedor;
	}

	public void imprimirFactura() {
		List<FacturaReporte> list = new ArrayList<FacturaReporte>();
		for (int i = 0; i < egreso.getDetalleegresos().size(); i++)
			list.add(egresoService.asignar(egreso.getDetalleegresos().get(i),
					listaFacturaReporte.get(i), 1));

		egresoReport.reporteFactura(egreso,
				clienteService.obtenerPorPersonaId(cliente.getPersonaid()),
				cantidadFacturaCalculos, list);
		cancelarTodo();
	}

	@PostConstruct
	public void init() {
		setListaLocales(localService.obtenerPorCajero(SecurityContextHolder
				.getContext().getAuthentication().getName()));

		listaVendedores = empleadoService.obtenerPorCargo(5);
		listaTransportistas = empleadoService.obtenerPorCargo(6);
		listaMotivotraslados = motivoTrasladoService.obtener(true);
		xxx();
	}

	public void insertar(ActionEvent actionEvent) {
		comprobarCabecera();

		if (comprobarCantidadFinal() && comprobarDetalleEgreso()) {
			bn = false;

			boolean pagado = true;

			List<Entrada> list = egreso.getEntradas();

			if (list.isEmpty() && egreso.getCredito() == null)
				pagado = false;

			for (Entrada e : list)
				if (e.getPagado() == false
						|| e.getCuota().compareTo(
								cantidadFacturaCalculos.getTotal()) < 0)
					pagado = false;

			if (egreso.getCredito() != null)
				if (egreso.getCredito().getPagado() == false)
					pagado = false;

			egreso.setPagado(pagado);

			if (guia == true
					&& guiaRemision.getMotivotraslado().getMotivotrasladoid() != 0
					&& transportista.getEmpleadocargoid() != 0
					&& guiaRemision.getPlaca() != null) {
				Local local = localService.obtenerPorLocalId(egreso.getLocal()
						.getLocalid());
				guiaRemision.setEgresos(new ArrayList<Egreso>());
				guiaRemision.addEgreso(egreso);
				guiaRemision.setFechainicio(new Date());
				guiaRemision.setFechaterminacion(new Date());
				guiaRemision.setPuntopartida(local.getCiudad());
				guiaRemision.setPuntollegada(cliente.getCiudad().getNombre());
				guiaRemision.setTransportistaid(transportista);
				guiaRemision.setRazonsocialdestinatario(cliente.getCliente()
						.getNombrecomercial());

				guiaRemision.setMotivotraslado(motivoTrasladoService
						.obtenerPorMotivoTrasladoId(guiaRemision
								.getMotivotraslado().getMotivotrasladoid()));
				// guiaRemision.setTransportista(transportistaService
				// .obtenerPorTransportistaId(guiaRemision
				// .getTransportista().getTransportistaid()));
				// egreso.setGuiaremision(guiaRemision);

			}

			egresoService.insertar(egreso, bodega);
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_INFO,
					"INSERTÓ", "Egreso: " + egreso.getCodigodocumento()));
		}
	}

	private void insertarDetalle() {
		facturaReporte = listaFacturaReporte.get(fila);

		producto = productoService.obtenerPorProductoId(producto
				.getProductoid());

		Kardex kardex = kardexService.obtenerSaldoActual(producto.getEan(),
				bodega.getBodegaid());

		if (cantidad <= kardex.getCantidad() && cantidad > 0) {
			Detalleegreso detalleEgreso = new Detalleegreso();

			detalleEgreso.setProducto(producto);
			facturaReporte.setCantidad(cantidad);

			facturaReporte = egresoService.asignar(detalleEgreso,
					facturaReporte, 0);

			detalleEgreso.setCantidad(facturaReporte.getCantidad());
			detalleEgreso.setPreciocosto(kardex.getPrecio());
			detalleEgreso.setPrecioventa(facturaReporte.getPrecioUnitVenta());
			detalleEgreso.setIva(producto.getIva());
			detalleEgreso.setPromocion(facturaReporte.isPromocion());
			detalleEgreso.setEliminar(facturaReporte.isEliminar());

			cantidadFacturaCalculos = egresoService.calcularCantidadFactura(
					cantidadFacturaCalculos, facturaReporte, "add");

			listaFacturaReporte.set(fila, facturaReporte);
			listaFacturaReporte.add(new FacturaReporte());
			egreso.addDetalleegreso(detalleEgreso);

			restante = restanteAux = cantidadFacturaCalculos.getTotal();
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_INFO,
					"INSERTÓ DETALLE", "INSERTO: " + producto.getEan()));
			limpiarFacturaReporte();
			producto = new Producto();
		} else
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"ERROR", "INGRESE UNA CANTIDAD MENOR A LA EXISTENTE: "
							+ kardex.getCantidad() + " O MAYOR QUE CERO"));
	}

	public boolean isBn() {
		return bn;
	}

	public boolean isGuia() {
		return guia;
	}

	public void limpiarFacturaReporte() {
		facturaReporte = new FacturaReporte();
	}

	private void metodo() {
		producto = productoService.obtenerPorCodigosAndLocal(egreso.getLocal()
				.getLocalid(), listaFacturaReporte.get(fila).getCodigo());
		Integer precioId = productoService.obtenerPvpPorProducto(producto
				.getTipoPrecioProductos());

		if (precioId != null) {
			facturaReporte.setProductoId(producto.getProductoid());
			facturaReporte.setPrecioId(precioId);
			facturaReporte.setCodigo(producto.getEan());
			facturaReporte.setDescripcion(producto.getNombreimprimir());
			if (producto.getIva())
				facturaReporte.setIva("I");
			else
				facturaReporte.setIva("");
			facturaReporte.setEliminar(true);
			facturaReporte.setPrecioUnitVenta(productoService.calcularPrecio(
					producto, bodega.getBodegaid(),
					facturaReporte.getPrecioId()));

			listaFacturaReporte.set(fila, facturaReporte);
			limpiarFacturaReporte();
		} else
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"MENSAJE DEL SISTEMA",
					"EL PRODUCTO NO TIENE CONFIGURADO SU PVP"));

		fila = null;
	}

	public void obtenerBodega() {
		Local local = localService.obtenerPorLocalId(egreso.getLocal()
				.getLocalid());
		if (local.getBodegalocals() != null
				&& !local.getBodegalocals().isEmpty())
			bodega = local.getBodegalocals().get(0).getBodega();
	}

	public void obtenerFila(CellEditEvent event) {
		fila = event.getRowIndex();
	}

	public void obtenerPrecio() {

	}

	private void presentaMensaje(FacesMessage message) {
		FacesContext.getCurrentInstance().addMessage(null, message);
	}

	public void setBn(boolean bn) {
		this.bn = bn;
	}

	public void setCambio(BigDecimal cambio) {
		this.cambio = cambio;
	}

	public void setCantidad(Integer cantidad) {
		this.cantidad = cantidad;
	}

	public void setCantidadFacturaCalculos(
			CantidadFactura cantidadFacturaCalculos) {
		this.cantidadFacturaCalculos = cantidadFacturaCalculos;
	}

	public void setCantidadFacturaPresentar(
			CantidadFactura cantidadFacturaPresentar) {
		this.cantidadFacturaPresentar = cantidadFacturaPresentar;
	}

	public void setCliente(Persona cliente) {
		this.cliente = cliente;
	}

	public void setEgreso(Egreso egreso) {
		this.egreso = egreso;
	}

	public void setFacturaReporte(FacturaReporte facturaReporte) {
		this.facturaReporte = facturaReporte;
	}

	public void setFacturaReportes(List<FacturaReporte> listaFacturaReporte) {
		this.listaFacturaReporte = listaFacturaReporte;
	}

	public void setGuia(boolean guia) {
		this.guia = guia;
	}

	public void setGuiaRemision(Guiaremision guiaRemision) {
		this.guiaRemision = guiaRemision;
	}

	public void setListaLocales(List<Local> listaLocales) {
		this.listaLocales = listaLocales;
	}

	public void setListaMotivotraslados(
			List<Motivotraslado> listaMotivotraslados) {
		this.listaMotivotraslados = listaMotivotraslados;
	}

	public void setListaTransportistas(
			List<PersonaCedulaNombre> listaTransportistas) {
		this.listaTransportistas = listaTransportistas;
	}

	public void setListaVendedores(List<PersonaCedulaNombre> listaVendedores) {
		this.listaVendedores = listaVendedores;
	}

	public void setNuevoPrecio(BigDecimal nuevoPrecio) {
		this.nuevoPrecio = nuevoPrecio;
	}

	public void setProducto(Producto producto) {
		this.producto = producto;
	}

	public void setRestante(BigDecimal restante) {
		this.restante = restante;
	}

	public void setRestanteAux(BigDecimal restanteAux) {
		this.restanteAux = restanteAux;
	}

	public void setTotalMonto(BigDecimal totalMonto) {
		this.totalMonto = totalMonto;
	}

	public void setTransportista(Empleadocargo transportista) {
		this.transportista = transportista;
	}

	public void setVendedor(Empleadocargo vendedor) {
		this.vendedor = vendedor;
	}

	private void xxx() {
		egreso = new Egreso();
		guiaRemision = new Guiaremision();
		guiaRemision.setMotivotraslado(new Motivotraslado());
		egreso.setLocal(new Local());
		vendedor = new Empleadocargo();
		transportista = new Empleadocargo();

		egreso.setEntradas(new ArrayList<Entrada>());
		egreso.setDetalleegresos(new ArrayList<Detalleegreso>());
		egreso.setTipodocumento(tipoDocumentoService.obtenerPorId(1));

		egreso.setCodigodocumento(parametro
				.getCodigoestablecimiento()
				.concat("-")
				.concat(parametro
						.getCodigoemision()
						.concat("-")
						.concat(String.format("%09d",
								parametro.getSecuenciafactura() + 1))));

	}

}